package engine

type RequestChan chan Request
type ResultChan chan ParseResult

type WorkerNotify interface {
    WorkerReady(RequestChan)
}

type Scheduler interface {
    Submit(Request)
    Run()
    WorkerChan() RequestChan
    WorkerNotify
}

type Processor func(request Request) ParseResult

type ConcurrentEngine struct {
    Scheduler        Scheduler
    WorkCount        uint32
    ItemChan         chan interface{}
    RequestProcessor Processor
}

func (e *ConcurrentEngine) Run(seeds ...Request) {
    out := make(ResultChan)
    
    e.Scheduler.Run()
    
    for i := uint32(0); i < e.WorkCount; i++ {
        in := e.Scheduler.WorkerChan()
        e.startWorker(in, out, e.Scheduler)
    }
    
    //e.Scheduler.ConfigMasterWorkerChan(in)
    for _, v := range seeds {
        e.Scheduler.Submit(v)
    }
    
    for result := range out {
        
        for _, item := range result.Items {
            go func(i interface{}) { e.ItemChan <- i }(item)
        }
        
        for _, v := range result.Requests {
            e.Scheduler.Submit(v)
        }
    }
}

func (e *ConcurrentEngine) startWorker(in RequestChan, out ResultChan, notify WorkerNotify) {
    go func() {
        for {
            notify.WorkerReady(in)
            req := <-in
            result := e.RequestProcessor(req)
            out <- result
        }
    }()
}
